﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Belyn.Common.API
{
    public class SetGlobalMouseHookSetWindowsHookException : Exception
    {
        public SetGlobalMouseHookSetWindowsHookException(string exceptionMsg) : base(exceptionMsg) { }
    }

    public class GlobalMouseHookHookEventAgrs : EventArgs
    {
        public MouseHookStruct MouseParam { get; private set; }
        public GlobalMouseHookHookEventAgrs(MouseHookStruct mouseParam)
        {
            MouseParam = mouseParam;
        }
    }
    public class GlobalMouseHook
    {
        public event Action<object, GlobalMouseHookHookEventAgrs> OnMouseHook; 
 
        public GlobalMouseHook()
        {
            
        }

        protected IntPtr CurrentHookHandle { get; private set; }
        private Belyn.Common.API.HookProc currentHookProc = null;
        protected Belyn.Common.API.HookProc CurrentHookProc
        {
            get
            {
                if (currentHookProc == null)
                {
                    currentHookProc = new Belyn.Common.API.HookProc(MyMouseHookProc);
                }
                return currentHookProc;
            }
        }
         
        public void StartHook()
        {
            using (Process curProcess = Process.GetCurrentProcess())
            {
                using (ProcessModule curModule = curProcess.MainModule)
                {
                    //IntPtr pInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule);
                    IntPtr pInstance = Belyn.Common.API.WinAPI.GetModuleHandle(curModule.ModuleName);
                    CurrentHookHandle = Belyn.Common.API.WinAPI.SetWindowsHookEx((int)HookType.WH_MOUSE_LL, CurrentHookProc, pInstance, 0);
                }
            }

            if (CurrentHookHandle == IntPtr.Zero)
            {
                throw new SetGlobalMouseHookSetWindowsHookException("SetWindowsHookEx失败,错误信息："+Marshal.GetLastWin32Error());
            }
        }

        /// <summary>
        /// 註冊Windows Hook時用到的委派方法，當全域事件發生時會執行這個方法，並提供全域事件資料。
        ///  
        /// </summary>
        protected int MyMouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)// ref Belyn.Common.API.KeyBoardHookStruct cwp)
        {

            Belyn.Common.API.MouseHookStruct cwp = (Belyn.Common.API.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Belyn.Common.API.MouseHookStruct));
            //Dictionary<string, string> messageList = new Dictionary<string, string>();
            //messageList.Add("nCode", nCode + "");
            //messageList.Add("wParam", wParam + "");
            //messageList.Add("cwp.dwExtraInfo", cwp.dwExtraInfo + "");
            //messageList.Add("cwp.flags", cwp.flags + "");
            //messageList.Add("cwp.scanCode", cwp.scanCode + "");
            //messageList.Add("cwp.time", cwp.time + "");
            //messageList.Add("cwp.vkCode", cwp.vkCode + "");

            if (this.OnMouseHook != null)
            {
                this.OnMouseHook(this, new GlobalMouseHookHookEventAgrs(cwp));
            }

            
            return Belyn.Common.API.WinAPI.CallNextHookEx(CurrentHookHandle, nCode, wParam, lParam);
        }

        public void StopHook()
        {
            if (CurrentHookHandle != IntPtr.Zero)
            {
                var result = Belyn.Common.API.WinAPI.UnhookWindowsHookEx(CurrentHookHandle);
                if (result)
                {
                    CurrentHookHandle = IntPtr.Zero;
                }
            }
        }

        ~GlobalMouseHook()
        {
            StopHook();
        }

    }
}
